package com.blustc.detect.ane.androino;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Handler;
import android.util.Log;

public class ArduinoService implements Runnable {

    private static final int GT540_SAMPLE_FREQ = 44100; // LG GT540
    private static final int AUDIO_SAMPLE_FREQ = GT540_SAMPLE_FREQ;
    private static final int AUDIO_RECEIVE_BUFFER_SIZE = 4096;

    private static final String TAG = "ArduinoService";

    private Handler mClientHandler;
    private FSKDecoder mDecoder;
    private static boolean forceStop = false;
    public static final int HANDLER_MESSAGE_FROM_ARDUINO = 2000;
    public static final int RECORDING_ERROR = -1333;

    int frequency = 17000;
    private short[] buffer = new short[AUDIO_SAMPLE_FREQ];
    private short[] sin;
    private int phase;

    public ArduinoService(Handler handler) {
        this.mClientHandler = handler;
        sin = generateSin();
    }

    @Override
    public void run() {
        this.forceStop = false;
        // Decoder initialization
        this.mDecoder = new FSKDecoder(this.mClientHandler);
        this.mDecoder.start();

        // Sound recording loop
        this.audioRecordingRun();
    }


    public void stopAndClean() {
        Log.i(TAG, "STOP stopAndClean():");
        this.forceStop = true;
    }

    private void audioRecordingRun() {

        // audio initialization
        int AUDIO_BUFFER_SIZE = 44100;
        int minBufferSize = AudioTrack.getMinBufferSize(AUDIO_SAMPLE_FREQ, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
        if (AUDIO_BUFFER_SIZE < minBufferSize) AUDIO_BUFFER_SIZE = minBufferSize;
        AudioTrack aT = new AudioTrack(AudioManager.STREAM_MUSIC,
                AUDIO_SAMPLE_FREQ, AudioFormat.CHANNEL_OUT_MONO,
                AudioFormat.ENCODING_PCM_16BIT, AUDIO_BUFFER_SIZE,
                AudioTrack.MODE_STREAM);
        aT.setStereoVolume(AudioTrack.getMaxVolume() , AudioTrack.getMaxVolume());
        aT.play();


        if (minBufferSize < AUDIO_RECEIVE_BUFFER_SIZE) {
            minBufferSize = AUDIO_RECEIVE_BUFFER_SIZE;
        }
        Log.i(TAG, "buffer size:" + minBufferSize);
        short[] audioData = new short[minBufferSize];



        AudioRecord aR = new AudioRecord(MediaRecorder.AudioSource.MIC,
                AUDIO_SAMPLE_FREQ, AudioFormat.CHANNEL_IN_MONO,
                AudioFormat.ENCODING_PCM_16BIT, minBufferSize);
        // audio recording
        aR.startRecording();

        this.forceStop = false;
        // continuous loop
        while (true) {
            fillBuffer(aT);
            int nBytes = aR.read(audioData, 0, audioData.length);
            Log.v(TAG, "audio acq: length=" + nBytes);
            if (nBytes < 0) {
                Log.e(TAG, "audioRecordingRun() read error=" + nBytes);
                this.mClientHandler.obtainMessage(ArduinoService.HANDLER_MESSAGE_FROM_ARDUINO, RECORDING_ERROR, 0).sendToTarget();
            }

            this.mDecoder.addSound(audioData, nBytes);

            if (this.forceStop) {
                this.mDecoder.stopAndClean();
                break;
            }
        }
        aT.stop();
        aT.release();
        aR.stop();
        aR.release();
        Log.i(TAG, "STOP audio recording stoped");

    }


    private short[] generateSin() {
        short[] returnArray = new short[AUDIO_SAMPLE_FREQ];
        for (int i = 0; i < AUDIO_SAMPLE_FREQ; i++) {
            returnArray[i] = (short) ((float) Short.MIN_VALUE * (Math.sin((2.0f * (float) Math.PI * ((float) i))
                    / ((float) AUDIO_SAMPLE_FREQ))));
        }
        return returnArray;
    }

    public void fillBuffer(AudioTrack aT) {
        for (int i = 0; i < buffer.length; i++) {
            phase %= sin.length;
            buffer[i] = sin[phase];
            phase += frequency;
        }
        aT.write(buffer, 0, buffer.length);
    }
}
